﻿using System;
using System.ServiceModel;
using System.Threading;
using CommonUtils;

namespace SearchFrontEnd
{
    using BackEndServerList = ServerList<SearchBackendClient, ISearchBackend>;
   
    /// <summary>
    /// Container for the main method of the front-end server.
    /// Here we create the service hosts that will enable receiving
    /// requests from the clients and the back-end servers.
    /// </summary>
    class FrontEndServer
    {
        private static ServiceHost frontEndHost = null;
        private static ServiceHost registryHost = null;
        private static FEGroupCommunication groupCom = null;
        public static int CACHE_SIZE = 3;

        /// <summary>
        /// Front end server's main method.
        /// </summary>
        /// <param name="args">
        /// A string array containing 3 elements:
        /// args[0] = front end port.
        /// args[1] = back end port.
        /// args[2] = results' cache size.
        ///  </param>
        public static void Main(String[] args)
        {           
            if (args.Length != 3)
            {
                Console.WriteLine("Bad arguments!");
                Console.WriteLine("Usage: SearchFrontHost.exe <front end port> <back end port> <cache size>");
                return;
            }

            CACHE_SIZE = Int32.Parse(args[2]);

            try
            {
                // Join FE servers group.
                groupCom = new FEGroupCommunication();

                // Start listening
                Thread groupThread = new Thread(groupCom.MainLoop);
                groupThread.Start();

                // Start the search FE and registry services.
                StartServices(args[0], args[1]);

                Console.WriteLine("Server up and running!");
                Console.WriteLine("Press the enter key to terminate the server.");
                Console.ReadLine();
            }
            catch (Exception e)
            {
                Print.ColorEmit(
                        String.Format(
                                "The following error occurred: {0}.", 
                                e.Message
                                ),
                        Print.Foreground.Red
                        );
                Print.ColorEmit("The server will be terminated.", Print.Foreground.Red);
            }
            finally
            {
                Console.Write("Closing...");

                //Leave group.
                if (groupCom != null)
                {
                    groupCom.Quit();  
                }
                
                //Close both services.
                CloseServices();


                //Close all opened clients.
                BackEndServerList.CloseAll();
                Console.WriteLine("Done.");
            }
        }

        /// <summary>
        /// Create the Search FE service, and the registry service for BE 
        /// servers.
        /// </summary>
        /// <param name="clientPort">The port on which client requests 
        /// are received.</param>
        /// <param name="bePort">The port on which BE server requests
        /// are received.</param>
        private static void StartServices(
                                string clientPort, 
                                string bePort
                                )
        {
            // Start SearchFrontEnd service
            Console.Write("Starting search Server... ");
            string uri = "http://localhost:" + clientPort + "/Services";
            frontEndHost = new ServiceHost(
                                    typeof(SearchFrontEnd), 
                                    new Uri(uri)
                                    );
            frontEndHost.Open();
            Console.WriteLine("Done!");

            // Start SearchRegistry service
            Console.Write("Starting backend server registry... ");
            uri = "net.tcp://localhost:" + bePort + "/Services";
            registryHost = new ServiceHost(
                                    typeof(SearchRegistry), 
                                    new Uri(uri)
                                    );
            ((NetTcpBinding)registryHost.Description.Endpoints[0].Binding).Security.Mode = SecurityMode.None;
            registryHost.Open();
            Console.WriteLine("Done!"); 
        }

        /// <summary>
        /// Closes services if they are started.
        /// </summary>
        private static void CloseServices()
        {
            if (frontEndHost != null)
            {
                frontEndHost.Close(); 
            }
            if (registryHost != null)
            {
                registryHost.Close();
            }
        }
    }
}
